package org.smartboot.compare.difference;

import org.smartboot.compare.Path;
import org.smartboot.compare.array.ArrayHelper;

import java.lang.reflect.Array;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
 * @author qinluo
 * @version 1.0.0
 * @date 2020-08-18 15:44
 */
public class BaseDifference extends AbstractDifference {

    /**
     * Expect object.
     */
    protected Object expect;

    /**
     * Actual object.
     */
    protected Object actual;

    public BaseDifference(Path path) {
        super(path);
    }

    public BaseDifference(Path path, Object expect, Object actual) {
        super(path);
        this.expect = expect;
        this.actual = actual;
    }

    public Object getExpect() {
        return expect;
    }

    public void setExpect(Object expect) {
        this.expect = expect;
    }

    public Object getActual() {
        return actual;
    }

    public void setActual(Object actual) {
        this.actual = actual;
    }

    @Override
    public String getMessage() {
        String expectDesc = expectDesc();
        String actualDesc = actualDesc();
        StringBuilder sb = new StringBuilder();
        sb.append(type()).append(", ").append(path);
        if (expectDesc != null && !Objects.equals(expectDesc, "")) {
            sb.append(", ").append(expectDesc).append(" [").append(cast(expect)).append("]");
        }
        if (actualDesc != null && !Objects.equals(actualDesc, "")) {
            sb.append(", ").append(actualDesc).append(" [").append(cast(actual)).append("]");
        }
        return sb.toString();
    }

    protected String expectDesc() {
        return "期望值";
    }

    protected String actualDesc() {
        return "实际值";
    }

    protected String cast(Object val) {
        if (val == null) {
            return "null";
        }

        Class<?> type = val.getClass();
        if (type.isArray()) {
            return String.valueOf(asSet(val));
        }

        if (type == Date.class) {
            return String.valueOf(((Date) val).getTime());
        }

        return String.valueOf(val);
    }

    public static Set<Object> asSet(Object array) {
        Set<Object> l = new HashSet<>();
        int length = ArrayHelper.getLength(array);
        for (int i = 0; i < length; i++) {
            l.add(Array.get(array, i));
        }

        return l;
    }

    @Override
    public Map<String, Object> getJsonViewModel() {
        Map<String, Object> jsonViewModel = new HashMap<>(4);
        jsonViewModel.put("type",  type());
        jsonViewModel.put("expect",  expect);
        jsonViewModel.put("actual",  actual);

        if (this.source != null) {
            jsonViewModel.put("source",  this.source.identifier());
        }

        return jsonViewModel;
    }

    @Override
    public String type() {
        return "Based";
    }
}
